flutter 开发技巧 |
您所在的位置:网站首页 › flutter 动画效果粒子 › flutter 开发技巧 |
本文主要包含两个方面:【路由导航】和【路由传值】 路由导航Flutter中管理多个页面时有两个核心概念和类:Route和Navigator。 一个route是一个屏幕或页面的抽象,Navigator是管理route的Widget。Navigator可以通过route入栈和出栈来实现页面之间的跳转。 路由一般分为静态路由(即命名路由)和动态路由。 ###静态路由(即命名路由) 静态路由在通过Navigator跳转之前,需要在MaterialApp组件内显式声明路由的名称,而一旦声明,路由的跳转方式就固定了。通过在MaterialApp内的routes属性进行显式声明路由的定义。 class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: "/", // 默认加载的界面,这里为RootPage routes: { // 显式声明路由 // "/":(context) => RootPage(), "/A":(context) => Apage(), "/B":(context) => Bpage(), "/C":(context) => Cpage(), }, home: RootPage(), ); } } 注意:如果指定了home属性,routes表则不能再包含此属性。 如上代码中【home: RootPage()】 和 【"/":(context) => RootPage()】两则不能同时存在。例如:RootPage跳转Apage即:RootPage?—>Apage Navigator.of(context).pushNamed("/A");一般方法中带有Name多数是通过静态路由完成跳转的,如pushNamed、pushReplacementNamed、pushNamedAndRemoveUntil等。 ###动态路由 动态路由无需在MaterialApp内的routes中注册即可直接使用:RootPage —> Apage Navigator.of(context).push(MaterialPageRoute( builder: (context) => Apage(), ));动态路由中,需要传入一个Route,这里使用的是MaterialPageRoute?,它可以使用和平台风格一致的路由切换动画,在iOS上左右滑动切换,Android上会上下滑动切换。也可以使用CupertinoPageRoute?实现全平台的左右滑动切换。 当然也可以自定义路由切换动画,使用PageRouteBuilder:使用FadeTransition?做一个渐入过渡动画。 Navigator.of(context).push( PageRouteBuilder( transitionDuration: Duration(milliseconds: 250), // //动画时间为0.25秒 pageBuilder: (BuildContext context,Animation animation, Animation secondaryAnimation){ return FadeTransition( //渐隐渐入过渡动画 opacity: animation, child: Apage() ); } ) );到现在为止,可能对路由有了一定的认识,,下面就结合具体方法来详细说明。 在这之前有必要说明:?Navigator.of(context).push和Navigator.push两着并没有特别的区别,看源码也得知,后者其实就是调用了前者。?of:获取Navigator当前已经实例的状态。 ###pop 返回当前路由栈的上一个界面。?Navigator.pop(context); push / pushNamed :见上,两者运行效果相同,只是调用不同,都是将一个page压入路由栈中。直白点就是push是把界面直接放入,pushNames是通过路由名的方式,通过router使界面进入对应的栈中。 结果:直接在原来的路由栈上添加一个新的?page。 pushReplacement / pushReplacementNamed / popAndPushNamed替换路由,顾名思义替换当前的路由。 例如 由图可知在BPage使用替换跳转到Cpage的时候,Bpage被Cpage替换了在堆栈中的位置而移除栈,CPage默认返回的是APage。 pushReplacement 使用的动态路由方式跳转: Navigator.of(context).pushReplacement(MaterialPageRoute( builder: (context) => Cpage(), )); pushReplacementNamed 使用的静态路由方式, Navigator.of(context).pushReplacementNamed("/C");两者运行效果相同。 popAndPushNamed: Navigator.of(context).popAndPushNamed("/C");其实和上面两个方法运行的结果也是一致,区别就是动画效果不一样:BPage?—>CPage的时候,CPage会同时有pop的转场效果和从BPage页push的转场效果。简单来说就是CPage先pop到BPage,在push到CPage。(不知道是不是卡顿的原因,笔者看起来区别不大) 综上:3中方法结果一样,只是调用方式和过渡动画的区别,开发者自行选择。 pushAndRemoveUntil / pushNamedAndRemoveUntil在使用上述方式跳转时,会按次序移除其他的路由,直到遇到被标记的路由(predicate函数返回了true)时停止。若 没有标记的路由,则移除全部。 当路由栈中存在重复的标记路由时,默认移除到最近的一个停止。 第一种 // 移除全部 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), (Route router) => router == null);或 // 移除全部 Navigator.of(context).pushNamedAndRemoveUntil("/C", (Route router) => router == null);此时的路由栈示意图: 可知出了要push的CPage,当前路由栈中所有的路由都被移除,CPage变成根路由。 第二种:移除到RootPage停止 // "/"即为RootPage,标记后,移除到该路由停止移除 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), ModalRoute.withName('/')) 或 Navigator.pushAndRemoveUntil(context, MaterialPageRoute(builder: (_) => CPage()), (Route router) => router.settings.name == "/"); // 只是写法不一样或 Navigator.of(context).pushNamedAndRemoveUntil("/C", (Route router) => router.settings.name == "/"); 或 Navigator.of(context).pushNamedAndRemoveUntil("/C", ModalRoute.withName("/"));此时的路由栈示意图: push到CPage的时候,移除到RootPage停止,CPage默认返回RootPage。 popUntil返回到指定的标记路由,若标记的路由为null,则程序退出,慎用!!! 有时候我们需要根据业务需求判断:可能返回上一级路由,也可能返回上上级路由或是返回指定的路由等。这个时候就不能使用Replacement和RemoveUntil来替换、移除路由了。 例如: 再例如: 要实现上述功能,从CPage返回到APage,并且不在MaterialApp内的routes属性进行显式声明路由。因为笔者觉得一个应用程序的界面太多了,如果每个界面都要显示声明路由,实在是不优雅。 因为需要返回APage,还是需要标记路由,所有我们在之前跳转APage的时候设置RouteSettings,如下: // 设置APage的RouteSettings Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name:"/A"), builder: (context) => APage(), ));在CPage需要返回的时候,调用就行: Navigator.of(context).popUntil(ModalRoute.withName("/A"));这样代码看起来很优雅,不会冗余。 另: // 返回根路由 Navigator.of(context).popUntil((route) => route.isFirst); canPop用来判断是否可以导航到新页面,返回的bool类型,一般是在设备带返回的物理按键时需要判断是否可以pop。 maybePop可以理解为canPop的升级,maybePop?会自动判断。如果当前的路由可以pop,则执行当前路由的pop操作,否则将不执行。 removeRoute/removeRouteBelow删除路由,同时执行Route.dispose操作,无过渡动画,正在进行的手势也会被取消。 removeRouteBPage被移除了当前的路由栈。 如果在当前页面调用removeRoute?,则类似于调用pop方法,区别就是无过渡动画,所以removeRoute?也可以用来返回上一页。 removeRouteBelow移除指定路由底层的临近的一个路由,并且对应路由不存在的时候会报错。 同上。 综上:这个两个方法一般情况下很少用,而且必须要持有对应的要移除的路由。 一般用于立即关闭,如移除当前界面的弹出框等。 路由传值常见的路由传值分为两个方面: 向下级路由传值返回上级路由时传值要注意的是,我们一般说静态路由不能传值,并不是说一定不能用于传值,而是因为静态路由一般需要在MaterialApp内的routes属性进行显式声明,在这里使用构造函数传值无实际意义。 如: MaterialApp( initialRoute: "/", // 默认加载的界面,这里为RootPage routes: { // 显式声明路由 "/":(context) => RootPage(), "/A":(context) => APage("title"), // 在这里传参无实际意义,一般需要传入的参数都是动态变化的 "/B":(context) => BPage(), "/C":(context) => CPage(), }, // home: RootPage(), ); 向下级路由传值 1、构造函数传值首先构造一个可以带参数的构造函数: class APage extends StatefulWidget { String title; APage(this.title); @override _APageState createState() => _APageState(); }在路由跳转的时候传值: Navigator.of(context).push(MaterialPageRoute( builder: (context) => APage("这是传入的参数"), ));在APage拿到传入的值: // 在 StatefulWidget 使用[widget.参数名] Container( child: Text(widget.title), ) 复制代码 2、ModalRoute 传值在Navigator.of(context).push的跳转方式中,MaterialPageRoute?的构造参数中 可以看到有RouteSettings的属性,RouteSettings就是当前路由的基本信息 const RouteSettings({ this.name, this.isInitialRoute = false, this.arguments, // 存储路由相关的参数Object });路由跳转时设置传递参数: Navigator.of(context).push(MaterialPageRoute( settings: RouteSettings(name:"/A",arguments: {"argms":"这是传入A的参数"}), builder: (context) => APage(), )); 或使用静态路由pushName: Navigator.of(context).pushNamed("/A",arguments:{"argms":"这是传入A的参数"}); 复制代码在APage中取值: Map argms = ModalRoute.of(context).settings.arguments; print(argms["argms"]); 复制代码 返回上级路由时传值就是在调用APage中调用pop返回路由的时候传参 Navigator.of(context).pop("这是pop返回的参数值"); 复制代码在上一级路由获取: Navigator.of(context).push(MaterialPageRoute( builder: (context) => APage(), )).then((value){ // 获取pop的传值 print(value); }); 或 String value = await Navigator.of(context).pushNamed('/xxx'); |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |